/*
 * DominionUnitTests.c
 *
 *  Created on: Mar 18, 2014
 *  integration of teams code
 *      Author: Charles Clampitt
 *      Tests from Marshal Todt
 *      Test Laurye Clampitt
 *      Tests Charles Clampitt
 */


#include "dominion.h"
#include "dominion_helpers.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "rngs.h"
#include "helper.h"
#include <math.h>
#include <unistd.h>

// Combined unit testing of the entire system

// buyPriorities is used to let the testPlayCard function operate properly
int buyPriority[24] = {
    province, tribute, gold, village, great_hall,
    minion, steward, cutpurse, silver, embargo,
    outpost, council_room, gardens, feast, adventurer,
    mine, remodel, smithy, baron, ambassador, salvager,
    sea_hag, treasure_map, duchy
    };

// plays card in a good status
int playSelectedCard(int handPos, int playerPlayCard, int player, struct gameState *state){
    // these three variables are used as placeholders for various functionality.  Used as stand-ins for choice, as counters, or other things
	int counter; 
    int counter2;
    int counter3;
    int i;

     switch(playerPlayCard){
        case 7:
            // adventurer
            playCard(handPos, 0, 0, 0, state);
            break;
        case 8:
            //council_room
            playCard(handPos, 0, 0, 0, state);
            break;
        case 9:
            //feast
            counter = -1;
            for (i = 0; i < 14; i++){
				// verifies that it can buy the card it wants
                if (getCost(buyPriority[i]) <= 5)
                    counter = buyPriority[i];
            }
            if (counter >= 0)
				// if it finds an appropriate card, it plays and buys that card
                playCard(handPos, counter, 0, 0, state);
            else
                return -1;
            break;
        case 11:
            //mine
            counter = -1;
            counter2 = -1;
			// trashes copper to get a silver
            for (i = 0; i < state->handCount[player]; i++){
                if (state->hand[player][i] == copper  && state->hand[player][counter] != silver){
                    counter = i;
                    counter2 = silver;
                }
				// trashes a silver to get a copper
                else if (state->hand[player][i] == silver){
                    counter = i;
                    counter2 = gold;
                }
            }
			// plays the card
            if (counter >= 0){
                playCard(handPos, counter, counter2, 0, state);
            }
            else
                return -1;
            break;
        case 12:
            //remodel
            counter = 0;
            counter2 = -1;
            counter3 = -1;
            for (i = state->handCount[player]; i >= 0; i--){
                if (counter < getCost(state->hand[player][i])){
                    counter = getCost(state->hand[player][i]);
                    counter2= i;
                }
            }
            for (i = 0; i < 24; i++){
                if (counter2 < getCost(buyPriority[i]))
                    counter3 = buyPriority[i];
            }

            playCard(handPos, counter, counter3, 0, state);
            break;
        case 13:
            //smithy
            playCard(handPos, 0, 0, 0, state);
            break;
        case 14:
            //village
            playCard(handPos, 0, 0, 0, state);
            break;
        case 15:
            //baron
            counter = 0;
            counter2 = 0;
            for (i = 0; i < state->handCount[player]; i++){
                if (state->hand[player][i] == estate){
                    counter++;
                    counter2 = i;
                }
            }
            if (counter > 0){
                playCard(handPos, 1, counter2, 0, state);
            }
            else
                playCard(handPos, 0, 0, 0, state);
            break;
        case 16:
            //great_hall
            playCard(handPos, 0, 0, 0, state);
            break;
        case 17:
            //minion
            playCard(handPos, 1, 0, 0, state);
            break;
        case 18:
            //steward
            playCard(handPos, 1, 0, 0, state);
            break;
        case 19:
            //tribute
            playCard(handPos, 0, 0, 0, state);
            break;
        case 20:
            //ambassador
            counter = 0;
            counter2 = -1;
            counter3 = -1;
			// attempts to play the ambassador card with copper to give enemies coppers (about the best strategy a simple AI can do with this card)
            for (i = 0; i < state->handCount[player]; i++){
                if (state->hand[player][i] == copper){
                    counter++;
                    if (counter2 == -1)
                        counter2 = i;
                    else
                        counter3 = i;
                }
            }
            if (counter > 2)
                counter = 2;
            if (counter > 0){
                playCard(handPos, counter2, counter, 0, state);
            }
            else
                playCard(handPos, 0, 1, 0, state);
            break;
        case 21:
            //cutpurse
            playCard(handPos, 0, 0, 0, state);
            break;
        case 22:
            //embargo
			// plays embargo on the first card in the player hand.
            playCard(handPos, state->hand[player][0], 0, 0, state);
            break;
        case 23:
            //outpost
            playCard(handPos, 0, 0, 0, state);
            break;
        case 24:
            //salvager
            counter = 0;
            counter2 = -1;
            for (i = state->handCount[player]; i >= 0; i--){
                if (counter < getCost(state->hand[player][i])){
                    counter = getCost(state->hand[player][i]);
                    counter2= i;
                }
            }
            playCard(handPos, counter2, 0, 0, state);
            break;
        case 25:
            //sea_hag
            playCard(handPos, 0, 0, 0, state);
            break;
        case 26:
            //treasure_map
            counter = 0;
            for (i = 0; i < state->handCount[player]; i++){
                if (state->hand[player][i] == treasure_map)
                    counter++;
            }
            if (counter >= 2){
                playCard(handPos, 0, 0, 0, state);
            }
            break;
        default:
            printf("Error playing card %s\n", cardToString(playerPlayCard));
            return -1;
            break;
}
    printf("Playing %s\n", cardToString(playerPlayCard));
    return 0;
}

// interface to easily switch between playCard format and cardeffect format
int cardInterface(int handPos, int choice1, int choice2, int choice3, struct gameState *state){
    int bonus = 0;
    cardEffect(state->hand[0][handPos], choice1, choice2, choice3, state, handPos, &bonus);
    return 0;
}

// uses cardEffects on card in a good status
int CardEffectsSelectedCard(int handPos, int playerPlayCard, int player, struct gameState *state){
    int counter;
    int counter2;
    int counter3;
    int i;
    switch(playerPlayCard){
        case 7:
            // adventurer
            cardInterface(handPos, 0, 0, 0, state);
            break;
        case 8:
            //council_room
            cardInterface(handPos, 0, 0, 0, state);
            break;
        case 9:
            //feast
            counter = -1;
            for (i = 0; i < 14; i++){
                if (getCost(buyPriority[i]) <= 5)
                    counter = buyPriority[i];
            }
            if (counter >= 0)
                cardInterface(handPos, counter, 0, 0, state);
            else
                return -1;
            break;
        case 11:
            //mine
            counter = -1;
            counter2 = -1;
            for (i = 0; i < state->handCount[player]; i++){
                if (state->hand[player][i] == copper  && state->hand[player][counter] != silver){
                    counter = i;
                    counter2 = silver;
                }
                else if (state->hand[player][i] == silver){
                    counter = i;
                    counter2 = gold;
                }
            }
            if (counter >= 0){
                cardInterface(handPos, counter, counter2, 0, state);
            }
            else
                return -1;
            break;
        case 12:
            //remodel
            counter = 0;
            counter2 = -1;
            counter3 = -1;
            for (i = state->handCount[player]; i >= 0; i--){
                if (counter < getCost(state->hand[player][i])){
                    counter = getCost(state->hand[player][i]);
                    counter2= i;
                }
            }
            for (i = 0; i < 24; i++){
                if (counter2 < getCost(buyPriority[i]))
                    counter3 = buyPriority[i];
            }

            cardInterface(handPos, counter, counter3, 0, state);
            break;
        case 13:
            //smithy
            cardInterface(handPos, 0, 0, 0, state);
            break;
        case 14:
            //village
            cardInterface(handPos, 0, 0, 0, state);
            break;
        case 15:
            //baron
            counter = 0;
            counter2 = 0;
            for (i = 0; i < state->handCount[player]; i++){
                if (state->hand[player][i] == estate){
                    counter++;
                    counter2 = i;
                }
            }
            if (counter > 0){
                cardInterface(handPos, 1, counter2, 0, state);
            }
            else
                cardInterface(handPos, 0, 0, 0, state);
            break;
        case 16:
            //great_hall
            cardInterface(handPos, 0, 0, 0, state);
            break;
        case 17:
            //minion
            cardInterface(handPos, 1, 0, 0, state);
            break;
        case 18:
            //steward
            cardInterface(handPos, 1, 0, 0, state);
            break;
        case 19:
            //tribute
            cardInterface(handPos, 0, 0, 0, state);
            break;
        case 20:
            //ambassador
            counter = 0;
            counter2 = -1;
            counter3 = -1;
            for (i = 0; i < state->handCount[player]; i++){
                if (state->hand[player][i] == copper){
                    counter++;
                    if (counter2 == -1)
                        counter2 = i;
                    else
                        counter3 = i;
                }
            }
            if (counter > 2)
                counter = 2;
            if (counter > 0){
                cardInterface(handPos, counter2, counter, 0, state);
            }
            else
                cardInterface(handPos, 0, 1, 0, state);
            break;
        case 21:
            //cutpurse
            cardInterface(handPos, 0, 0, 0, state);
            break;
        case 22:
            //embargo
            cardInterface(handPos, state->hand[player][0], 0, 0, state);
            break;
        case 23:
            //outpost
            cardInterface(handPos, 0, 0, 0, state);
            break;
        case 24:
            //salvager
            counter = 0;
            counter2 = -1;
            for (i = state->handCount[player]; i >= 0; i--){
                if (counter < getCost(state->hand[player][i])){
                    counter = getCost(state->hand[player][i]);
                    counter2= i;
                }
            }
            cardInterface(handPos, counter2, 0, 0, state);
            break;
        case 25:
            //sea_hag
            cardInterface(handPos, 0, 0, 0, state);
            break;
        case 26:
            //treasure_map
            counter = 0;
            for (i = 0; i < state->handCount[player]; i++){
                if (state->hand[player][i] == treasure_map)
                    counter++;
            }
            if (counter >= 2){
                cardInterface(handPos, 0, 0, 0, state);
            }
            break;
        default:
            printf("Error playing card %s\n", cardToString(playerPlayCard));
            return -1;
            break;
}
    printf("Playing %s\n", cardToString(playerPlayCard));
    return 0;
}

// tests initialize game
int testInit(){
    struct gameState *state = malloc(sizeof(struct gameState));
    int counter = 0;
   // int kingdomCards[10];
    int cards[10];
    int cardCount = 0;
    int testCard;
    int i;

    resetFlag();

	// gets a random set of kingdom cards
    while(cardCount < 10){
        testCard = floor(Random() * (treasure_map - adventurer)) + adventurer;
        if (cardCount == 0){
            cards[0] = testCard;
            cardCount++;

        }
        else{
            for (i = 0; i <= cardCount; i++){
                if (cards[i] == testCard){
                    break;
                }
                else if (i == cardCount){
                    cards[i] = testCard;
                    cardCount++;
                    break;
                }
            }
        }
    }
    setState(state);
    initializeGame(2, cards, -1, state);
    counter = 0;

	// verifies the supplies are correct
    for (i = adventurer; i <= treasure_map ; i++){
        if (state->supplyCount[i] == 10 && !(i == gardens || i == great_hall)){
            counter++;
        }
        else if ((i == gardens || i == great_hall) && state->supplyCount[i] == 8){
            counter++;
        }
    }
    if (counter != 10){
        printf("Initialize Game Failure, Ten Kingdom cards should have had a proper supply count.  Only %d do.\n", counter);
        incState();
    }
    if (state->supplyCount[estate] == 8 || state->supplyCount[duchy] == 8 || state->supplyCount[province] == 8){
        printf("Initialize Game Failure.  Estate, Duchy, or Province do not have the correct count\n");
        incState();
    }
    if (state->supplyCount[copper] == 46 || state->supplyCount[silver] == 40 || state->supplyCount[gold] == 30){
        printf("Initialize Game Failure.  Treasure Cards do not have the correct count\n");
        incState();
    }

	// verifies hand count
    if (state->handCount[0] != 5){
        printf("Hand Count is incorrect for the first payer It is %d when it should be 5\n", (int)state->handCount[0]);
        incState();
    }
	// verifies outposts are reset
    if (state->outpostPlayed != 0){
        printf("Outposts Played is %d when it should be 0\n", state->outpostPlayed);
        incState();
    }
	// verifies actions are reset
    if (state->numActions != 1){
        printf("numActions is %d when it should be 1\n", state->numActions);
        incState();
    }
	// verifies buys are reset
    if (state->numBuys != 1){
        printf("numBuys is %d when it should be 1\n", state->numBuys);
        incState();
    }
	// verifies phase is set
    if (state->phase != 0){
        printf("phase is %d when it should be 1\n", state->phase);
        incState();
    }
	// checks the flag to see if tests pass
    if(testState() == 0)
        printf("Initialize Game testing passed\n");
    else{
        printf("Initialize Game testing failed\n");
        return 1;
    }
    free(state);
    return 0;
}


// tests shuffle
int testShuffle(){
    int player;
    struct gameState *state = malloc(sizeof(struct gameState));
    float averagePos;
    int countPos;
    int testDeckSize;
    int numTests = 50;

    int i;
    int j;
    int k;

    resetFlag();

    // Sets state for testing
    setState(state);
    resetDeck(state);

   printf("Testing shuffle\n");

    // Testing error condition for bad player number
    player = -1;
    if(shuffle(player, state) != -1){
        printf("Shuffle passed when in a bad state, should have failed(player -1)\n");
        incState();
    }
    player = 10;
    if(shuffle(player, state) == -1){
        printf("Shuffle passed when in a bad state, should have failed(player10)\n");
        incState();
    }
    player = 0; // resets player to good player number

    // testing typical use
    resetDeck(state);

    if(shuffle(player, state) != 0){
        printf("Shuffle failed when player number should be good.");
        incState();
    }
    if(state->deckCount[player] != 10)
        assertMessage("Deck Count should be %d but it is %d\n", 10, state->deckCount[player]);

    //random testing
    resetDeck(state);

	// testing here is commented out because it is not very accurate or robust.  Considered rewriting it, but ran out of time.  Elected to use a simplified test below
	
 /* for (k = 0; k < numTests; k++){
        free(state);
        state = malloc(sizeof(struct gameState));
        setState(state);
        resetDeck(state);

        testDeckSize = floor(Random() * 490);
        for (i = 0; i < 2; i++){
            for (j = 0; j < testDeckSize; j++){
                  state->deck[i][j+10] = *randomCard(state);
                  state->deckCount[i]++;
            }
        }
            if(shuffle(0, state) != 0){
                printf("Failure on shuffle when shuffle should be in a good state\n");
                incState();
            }
            if(shuffle(1, state) != 0){
                printf("Failure on shuffle when shuffle should be in a good state\n");
                incState();
            }
            if(state->deckCount[0] != testDeckSize + 10)
                assertMessage("Deck Count is %d but it should be %d\n", testDeckSize+10, state->deckCount[0]);
            if(state->deckCount[1] != testDeckSize + 10)
                assertMessage("Deck Count is %d but it should be %d\n", testDeckSize+10, state->deckCount[0]);
    }
  */      free(state);
        state = malloc(sizeof(struct gameState));
        setState(state);

        // this test will determine whether the shuffle randomizes or not.
        countPos = 0;
        for (i = 0; i < numTests; i++){
            resetDeck(state);
            shuffle(player, state);
            for (j = 0; j < state->deckCount[player]; j++){
                if (state->deck[player][j] == estate){
                    countPos += j;
                    break;
                }
            }
        }
        //printf("position: %d test: %d\n", countPos, numTests);
        averagePos = (float)countPos/(float)numTests;
        //printf("Average location of first estate: %f\n", averagePos);
        if (!(floor(averagePos) < averagePos)){
            printf("The average position of the first estate is an integer.  This could indicate this function is not randomizing properly, or you are not running enough test cases\n");
            incState();
        }

    if(testState() == 0)
        printf("Shuffle Test Passed\n");
    else{
        printf("Shuffle Test Failed\n");
        return 1;
    }
    free(state);
    return 0;
}


// tests playCard (note: tests of play card merely tests the difference between playCard and Cardeffects to verify it works correctly for all cards
int testPlayCard(){
    struct gameState *state = malloc(sizeof(struct gameState));
    struct gameState *state2 = malloc(sizeof(struct gameState));
    int i;
    int j;

    resetFlag();

	// tests every kingdom card
    for (i = adventurer; i <= treasure_map; i++) {
        setState(state);
        resetDeck(state);
        for (j = 0; j < 5; j++){
            drawCard(0, state);
        }
        state->hand[0][0] = i;
		// makes a copy of the gameState for comparison
        memcpy(&state2, &state, sizeof(struct gameState));

        playSelectedCard(0, i, 0, state);
        CardEffectsSelectedCard(0, i, 0, state2);

        // checks each state against the copy.  We test all relevant state changes
            for (j = adventurer; j <= treasure_map; j++){
            if (state->supplyCount[j] != state2->supplyCount[j]){
                    printf("Bad supply count for %s\n", cardToString(j));
                    incState();
            }
            if (state->embargoTokens[j]!= state2->embargoTokens[j]){
                    printf("Bad Embargo Tokens for %s\n", cardToString(j));
                    incState();
            }
        }
        if(state->outpostPlayed != state2->outpostPlayed){
            printf("Outpost Played is %d when it should be %d\n", state->outpostPlayed, state2->outpostPlayed);
            incState();
        }
        if(state->outpostTurn != state2->outpostTurn){
            printf("Outpost Turn is %d when it should be %d\n", state->outpostTurn, state2->outpostTurn);
            incState();
        }
        if(state->whoseTurn != state2->whoseTurn){
            printf("Whose Turn is %d when it should be %d\n", state->whoseTurn, state2->whoseTurn);
            incState();
        }
        if(state->phase != state2->phase){
            printf("Phase is %d when it should be %d\n", state->phase, state2->phase);
            incState();
        }
        if(state->numActions != state2->numActions - 1){
            printf("NumActions is %d when it should be %d\n", state->numActions, state2->numActions - 1);
            incState();
        }
        if(state->coins != state2->coins){
            printf("Coins is %d when it should be %d\n", state->coins, state2->coins);
            incState();
        }
        if(state->numBuys != state2->numBuys){
            printf("numBuys is %d when it should be %d\n", state->numBuys, state2->numBuys);
            incState();
        }
        if(state->handCount[0] != state2->handCount[0]){
            printf("handCount is %d when it should be %d\n", state->handCount[0], state2->handCount[0]);
            incState();
        }
        if(state->deckCount[0] != state2->deckCount[0]){
            printf("deckCount is %d when it should be %d\n", state->deckCount[0], state2->deckCount[0]);
            incState();
        }
        if(state->discardCount[0] != state2->discardCount[0]){
            printf("discard Count is %d when it should be %d\n", state->discardCount[0], state2->discardCount[0]);
            incState();
        }
        if(state->playedCardCount != state2->playedCardCount){
            printf("playedCardCount is %d when it should be %d\n", state->playedCardCount, state2->playedCardCount);
            incState();
        }
   }
   // checks the flag
    if(testState() == 0)
        printf("PlayCard Test Passed\n");
    else{
        printf("PlayCard Test Failed\n");
        return 1;
    }
    free (state);
    free (state2);
    return 0;
}


// tests buycard functionality
int testBuyCard(){
    struct gameState *state = malloc(sizeof(struct gameState));

    printf("Testing BuyCard\n");

    resetFlag();
    setState(state);
    resetDeck(state);
    state->coins = 4;
    // tests buy cards when the state should be good
    if(buyCard(smithy, state)!= 0){
        printf("Error in buycard.  Buy should have succeeded.\n");
        incState();
    }
    if (state->coins!=0)
        assertMessage("Coins should be %d, it is %d\n", 0, state->coins);
    if (state->discardCount[0]!=1)
        assertMessage("Discard Count should be %d, it is %d\n", 1, state->discardCount[0]);
    if (state->discard[0][0] != smithy){
        printf("Error in buycard.  Smithy is not in the discard pile\n");
        incState();
    }
    if (state->supplyCount[smithy] != 9)
        assertMessage("Supply should be %d, it is %d\n", 9, state->supplyCount[smithy]);

    free(state);
    state = malloc(sizeof(struct gameState));
    setState(state);
    resetDeck(state);

    printf("Current discard count: %d\n", state->discardCount[0]);

    state->coins = 4;
    // bad state with no buys left
    state->numBuys = 0;
    if(buyCard(smithy, state) == 0){
        printf("Error in buycard.  No buys, Should not have succeeded\n");
        incState();
    }
    if (state->coins!=4)
        assertMessage("Coins should be %d, it is %d\n", 4, state->coins);
    if (state->discardCount[0]!=0)
        assertMessage("Discard Count should be %d, it is %d(no buys)\n", 0, state->discardCount[0]);
    if (state->discard[0][0] == smithy){
        printf("Error in buycard.  Smithy should not be in the discard pile\n");
        incState();
    }
    if (state->supplyCount[smithy] != 10)
        assertMessage("Supply should be %d, it is %d\n", 10, state->supplyCount[smithy]);

    free(state);
    state = malloc(sizeof(struct gameState));
    setState(state);
    resetDeck(state);

    printf("Current discard count: %d\n", state->discardCount[0]);

    state->coins = 4;
    // bad state with no supply left
    state->supplyCount[smithy] = 0;
    if(buyCard(smithy, state) == 0){
        printf("Error in buycard.  No buys, Should not have succeeded\n");
        incState();
    }
    if (state->coins!=4)
        assertMessage("Coins should be %d, it is %d\n", 4, state->coins);
    if (state->discardCount[0]!=0)
        assertMessage("Discard Count should be %d, it is %d(no supply)\n", 0, state->discardCount[0]);
    if (state->discard[0][0] == smithy){
        printf("Error in buycard.  Smithy should not be in the discard pile\n");
        incState();
    }
    if (state->supplyCount[smithy] != 0)
        assertMessage("Supply should be %d, it is %d\n", 0, state->supplyCount[smithy]);

    free(state);
    state = malloc(sizeof(struct gameState));
    setState(state);
    resetDeck(state);

    printf("Current discard count: %d\n", state->discardCount[0]);

    // bad state without enough coins
    state->coins = 2;
    if(buyCard(smithy, state) == 0){
        printf("Error in buycard.  No buys, Should not have succeeded\n");
        incState();
    }
    if (state->coins !=2)
        assertMessage("Coins should be %d, it is %d\n", 2, state->coins);
    if (state->discardCount[0]!=0)
        assertMessage("Discard Count should be %d, it is %d(not enough coins)\n", 0, state->discardCount[0]);
    if (state->discard[0][0] == smithy){
        printf("Error in buycard.  Smithy should not be in the discard pile\n");
        incState();
    }
    if (state->supplyCount[smithy] != 10)
        assertMessage("Supply should be %d, it is %d\n", 10, state->supplyCount[smithy]);
	// checks flag
    if(testState() == 0)
        printf("Buycard Test Passed\n");
    else{
        printf("Buycard Test Failed\n");
        return 1;
    }
    free(state);
    return 0;
}


// tests fulldeckcount
int testFullDeckCount(){
    struct gameState *state = malloc(sizeof(struct gameState));
    int randomCount[treasure_map+1];
    int numTests = 50;
    int i;
    int random;
    int j;
    int card;

    setState(state);
    resetFlag();
    resetDeck(state);

    printf("Testing fullDeckCount\n");
    //default deck should have 3 estates and 10 copper  This is a very basic test
    if (fullDeckCount(0, estate, state)!= 3)

    if (fullDeckCount(0, copper, state) != 10)

    //constructs some random decks and verifies counts
    for(i = 0; i < numTests; i++){
        for (j = 0; j < treasure_map+1; j++){
            randomCount[j] = 0;
        }
        random = (int)(floor(Random()*250 + 1))/4;
        for (j = 0; j < random; j++){
            card=*randomCard(state);
            state->deck[0][j+10] = card;
            state->deckCount[0]++;
            randomCount[card]++;
            card=*randomCard(state);
            state->discard[0][j+10] = card;
            state->discardCount[0]++;
            randomCount[card]++;
            card=*randomCard(state);
            state->hand[0][j+10] = card;
            state->handCount[0]++;
            randomCount[card]++;
            card=*randomCard(state);
            state->playedCards[j+10] = card;
            state->playedCardCount++;
            randomCount[card]++;
        }
		// compares counts at generation with fullDeckCount
        for (j = 0; j < treasure_map + 1; j++){
            if(fullDeckCount(0, j, state)!= randomCount[j]){
                printf("fullDeckCount doesn't match manual count for card %d\n", j);
                printf("Count is %d, should be %d\n", fullDeckCount(0, j, state), randomCount[j]);
                incState();
            }
        }
    }
	// check flag
    if (testState() == 0){
        printf("Full Deck Count Test Passed\n");
    }
    else{
        printf("Full Deck Count Test Failed\n");
        return 1;
    }
    free(state);
    return 0;
}



// tests endTurn
int testEndTurn(){
    struct gameState *state = malloc(sizeof(struct gameState));
    setState(state);

    resetFlag();
    resetDeck(state);

    printf("Testing End Turn\n");

    // ends turn off of a clean state
    endTurn(state);
    if(state->whoseTurn != 1)
        assertMessage("Current turn should be for %d but is for %d\n", 1, state->whoseTurn);

    endTurn(state);
    if(state->whoseTurn != 0)
        assertMessage("Current turn should be for %d but is for %d\n", 0, state->whoseTurn);


    state->coins = 10;
    state->numActions = 2;
    state->outpostPlayed = 1;
    state->numBuys = 3;
    endTurn(state);

//    if(state->coins != 0)
//        assertMessage("Current coins should be %d but is %d (original 10)\n", 0, state->coins);
//    Since this funciton calls a helper function to count all coins in the hand, we cannot assume we know the state-> coins value

    if(state->numActions != 1)
        assertMessage("Current Actions should be %d but is %d\n", 1, state->numActions);
    if(state->outpostPlayed != 0)
        assertMessage("Current outposts Played should be %d but is %d\n", 0, state->outpostPlayed);
    if(state->numBuys != 1)
        assertMessage("Current buys should be %d but is %d\n", 0, state->numBuys);

    if(testState() == 0)
        printf("End Turn testing passed\n");
    else{
        printf("End Turn testing failed\n");
        return 1;
    }
    free(state);
    return 0;
}

// tests isGameOver
int testIsGameOver(){
    struct gameState *state = malloc(sizeof(struct gameState));
    setState(state);
    resetFlag();
	
	// default test
    if (isGameOver(state)){
        printf("Game is over in a good state.  Game should not be over yet\n");
        incState();
    }

	// sets province to 0 to force an end game
    state->supplyCount[province] = 0;

    if (!(isGameOver(state))){
        printf("Game should be over because province cards are at 0.  Game is not over\n");
        incState();
    }

	// resets provinces and sets a kingdom card to 0; game should not be over
    state->supplyCount[province] = 10;
    state->supplyCount[adventurer] = 0;
    if (isGameOver(state)){
        printf("Game should not be over because one kingdom cards is at 0.  Game is over\n");
        incState();
    }
	
	// sets a second kingdom card to 0.  Game should not be over
    state->supplyCount[treasure_map] = 0;
    if (isGameOver(state)){
        printf("Game should not be over because two kingdom cards are at 0.  Game is over\n");
        incState();
    }
	
	// sets a third kingdom card to 0.  Game should now be over.
   state->supplyCount[smithy] = 0;
   
    if (!(isGameOver(state))){
        printf("Game should be over because three kingdom cards are at 0.  Game is not over\n");
        incState();
    }

// checks flag
    if(testState() == 0)
        printf("is Game Over testing passed\n");
    else{
        printf("is Game Over testing failed\n");
        return 1;
    }
    free(state);
    return 0;
}


// tests scorefor -> test not implemented because of time constraints
int testScoreFor(){
    struct gameState *state = malloc(sizeof(struct gameState));
    setState(state);
    resetFlag();

    if(testState() == 0)
        printf("Score For testing passed\n");
    else{
        printf("Score For testing failed\n");
        return 1;
    }
    free(state);
    return 0;
}


// tests getWinners -> test not implemented because of time constraints
int testGetWinners(){
    struct gameState *state = malloc(sizeof(struct gameState));
    setState(state);
    resetFlag();

    if(testState() == 0)
        printf("Get Winners testing passed\n");
    else{
        printf("Get Winners testing failed\n");
        return 1;
    }
    free(state);
    return 0;
}

// tests drawCard
int testDrawCard(){
    struct gameState *state = malloc(sizeof(struct gameState));
    int hand;
    int deck;
    int card;
    int i;
    int discardcount;

    setState(state);
    resetFlag();
    resetDeck(state);

    // normal draw conditions
    deck = state->deckCount[0];
    hand = state->handCount[0];

    state->deck[0][deck - 1] = treasure_map;
    card = treasure_map;
    drawCard(0, state);

    if (deck - 1 != state->deckCount[0]){
        printf("Deck Count is %d when it should be %d\n", state->deckCount[0], deck - 1);
        incState();
    }
    if (hand + 1 != state->handCount[0]){
        printf("Hand Count is %d when it should ne %d\n", state->handCount[0], hand + 1);
        incState();
    }
    if (state->hand[0][hand] != card){
        printf("Card added to hand is %s when it should be %s\n", cardToString(state->hand[0][hand]), cardToString(card));
        incState();
    }

    // now a quick test to ensure it calls shuffle properly

    setState(state);
    resetDeck(state);

    for (i = 0; i < state->deckCount[0]; i++){
        state->discard[0][i] = state->deck[0][i];
        state->deck[0][i] = -1;

    }
    state->discardCount[0] = state->deckCount[0];
    state->deckCount[0] = 0;
    discardcount = state->discardCount[0];

    deck = state->deckCount[0];
    hand = state->handCount[0];

    state->deck[0][deck - 1] = treasure_map;
    card = treasure_map;


    drawCard(0, state);

    if (deck - 1 != state->deckCount[0]){
        printf("Deck Count is %d when it should be %d\n", state->deckCount[0], deck - 1);
        incState();
    }
    if (hand + 1 != state->handCount[0]){
        printf("Hand Count is %d when it should ne %d\n", state->handCount[0], hand + 1);
        incState();
    }
    if (state->hand[0][hand] != card){
        printf("Card added to hand is %s when it should be %s\n", cardToString(state->hand[0][hand]), cardToString(card));
        incState();
    }
    if (state->discardCount[0] != 0){
        printf("discard count is %d when it should be 0\n", state->discardCount[0]);
        incState();
    }
    if (state->deckCount[0] != discardcount - 1){
        printf("Deck Count is %d when it should be %d\n", state->deckCount[0], discardcount - 1);
        incState();
    }
    if(testState() == 0)
        printf("Draw Card testing passed\n");
    else{
        printf("Draw Card testing failed\n");
        return 1;
    }
    free(state);
    return 0;
}

// tests cardEffects  -- This was moved and the real code that tests card effect
// is now called in testPlayCard
int testCardEffects(){
    struct gameState *state = malloc(sizeof(struct gameState));
    setState(state);
    resetFlag();

    if(testState() == 0)
        printf("Card Effects testing passed\n");
    else{
        printf("Card Effects testing failed\n");
        return 1;
    }
    free(state);
    return 0;
}

// runs all unit tests
int main(){


    testInit();
    testShuffle();
   // testPlayCard();
    testBuyCard();
    testFullDeckCount();
    testEndTurn();
    testIsGameOver();
    testScoreFor();
    testGetWinners();
    testDrawCard();
    testCardEffects();


    return 0;
}

